﻿/*****************************************************
 * 本类库的核心系 JNTemplate
 * (C) JNTemplate 2011
 * 作者：翅膀的初衷 QQ:4585839
 * 网址：http://www.JiNianNet.com
 *****************************************************/

//#define NOSAFE
#define ALLOWIF
//#define ALLOWFOR

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using JinianNet.JNTemplate.Process.Element;

namespace JinianNet.JNTemplate.Process
{
    public class TemplateParser
    {
        public virtual Token ProcessTag(string text, List<Token> element, ref int index)
        {
            Token token;
            if (string.IsNullOrEmpty(text))
            {
                return new Token(TokenKind.Text, text);
            }

            if (element.Count > 0)
            {
                token = ProcessCompositeTag(text, element, ref index);
                if (token != null)
                    return token;
            }

            token = ProcessSimpleTag(text);
            if (token != null)
                return token;

            token = new Token(TokenKind.Text, text);
            return token;
        }

        public bool IsEscape(string value, int index)
        {
            index--;
            if (index >= 0)
            {
                if (value[index] == '\\')
                {
                    if (!IsEscape(value, index))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public object ProcessString(string value)
        {

            //只判断如下类型 布尔，字符串，数字，标签
            if (string.IsNullOrEmpty(value))
                return value;

            value = value.Trim();

            if (value == "true")
            {
                return true;
            }

            if (value == "false")
            {
                return false;
            }

            if (value[0] == '"' && value[value.Length - 1] == '"')
            {
                value = value.Remove(value.Length - 1, 1).Remove(0, 1);
                int startIndex = 0;
                bool check = true;
                while (true)
                {

                    int index = value.IndexOf('"', startIndex);
                    if (index >= 0)
                    {
                        if (IsEscape(value, index))
                        {
                            startIndex = index;
                            value = string.Concat(value.Substring(0, index - 1), value.Substring(index));
                        }
                        else
                        {
                            check = false;
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                if (check)
                {
                    return (string)value;
                }
            }

            if (Char.IsNumber(value[0]) && Char.IsNumber(value[value.Length - 1]))
            {
                if (ParserRegex.Number.Match(value).Success)
                    return int.Parse(value);
                if (ParserRegex.Double.Match(value).Success)
                    return double.Parse(value);
            }

            Token token = ProcessSimpleTag(value);
            if (token != null)
                return token;

            return new Token(TokenKind.Text, value);//未知的对象
        }


        public List<object> Split(string value, params char[] separator)
        {
            return Split(value, false, separator);
        }

        public List<object> Split(string str, bool reserves, params char[] separator)
        {
            List<object> ListContair = new List<object>();
            List<char> separators = new List<char>(separator);
            int startChar = 0;
            bool isString = false;
            for (int i = 0; i < str.Length; i++)
            {
                if (str[i] == '"' && !IsEscape(str, i))
                {
                    isString = !isString;
                }
                else
                {
                    if (!isString && separators.Contains(str[i]))
                    {
                        if (!isString)
                        {
                            string str1;
                            if (startChar == i)
                                str1 = string.Empty;
                            else
                                str1 = str.Substring(startChar, i - startChar);

                            ListContair.Add(ProcessString(str1));
                            startChar = i + 1;
                            if (reserves)
                            {
                                ListContair.Add(str[i].ToString());
                            }
                        }
                    }
                }
            }
            if (startChar < str.Length)
            {
                ListContair.Add(ProcessString(str.Substring(startChar, str.Length - startChar).Trim()));
            }
            return ListContair;
        }


        public virtual SimpleTag ProcessSimpleTag(string text)
        {
            text = text.Trim();
            #region set
            if (text.StartsWith("#set ", StringComparison.OrdinalIgnoreCase))
            {
                string _text = text.Remove(0, 4);
                int i = _text.IndexOf('=');
                if (i > 0)
                {
                    SetTag tag = new SetTag(text);
                    tag.Key = _text.Substring(0, i).Trim();
                    string simpValue = _text.Substring(i + 1, _text.Length - i - 1);
                    tag.Value = ProcessSimpleTag(simpValue);
                    if (tag.Value == null)
                    {
                        tag.Value = new Token(TokenKind.Text, simpValue);
                    }
                    return tag;
                }
                return null;
            }
            #endregion
            #region Load
            if (text.StartsWith("#load(", StringComparison.OrdinalIgnoreCase) && text.EndsWith(")"))
            {
                LoadTag tag = new LoadTag(text);
                tag.Path = text.Remove(0, 6).TrimEnd(')').Trim();
                //tag.BasePath = _context.CurrentPath;
                return tag;
            }
            #endregion
            #region Function
            if (text.EndsWith(")", StringComparison.OrdinalIgnoreCase) && text.IndexOf("(") > 0 && Char.IsLetter(text[0]))
            {
                int i = text.IndexOf('(');
                if (i > 0)
                {
                    FunctaionTag tag = new FunctaionTag(text);
                    tag.Method = text.Substring(0, i);
                    tag.Parameter = text.Substring(i, text.Length - i).TrimStart('(').TrimEnd(')').Trim();
                    return tag;
                }
                return null;
            }
            #endregion
            #region Variable
            if (ParserRegex.VariableRegex.Match(text).Success)
            {
                return new VariableTag(text);
            }
            #endregion
            return null;
        }


        public CompositeTag ProcessCompositeTag(List<Token> element, ref int index)
        {
            return ProcessCompositeTag(element[index].ToString(), element, ref index);
        }

        public CompositeTag ProcessCompositeTag(List<Token> element)
        {
            int index = 0;
            return ProcessCompositeTag(element, ref index);
        }

        public virtual CompositeTag ProcessCompositeTag(string text, List<Token> element, ref int index)
        {
            text = text.Trim();
            #region foreach
            if (text.StartsWith("#foreach(", StringComparison.OrdinalIgnoreCase))
            {
                string _text = text.Remove(0, 9).TrimEnd(')').Trim();
                int i = _text.IndexOf(" in ");
                if (i > 0)
                {
                    ForeachTag tag = new ForeachTag(text);
                    tag.Entity = _text.Substring(0, i).Trim();
                    tag.Source = _text.Substring(i + 4, _text.Length - i - 4).Trim();
                    tag.Cache = false;
                    index++;
                    while (true)
                    {
                        if (index < element.Count)
                        {
                            if (element[index].TokenKind == TokenKind.Tag)
                            {
                                if (element[index].ToString() != null && element[index].ToString().Trim().Equals("#endforeach", StringComparison.OrdinalIgnoreCase))
                                {
                                    break;
                                }
                                else
                                    tag.Element.Add(ProcessTag(element[index].ToString(), element, ref index));
                            }
                            else
                                tag.Element.Add(element[index]);
                            index++;
                        }
                        else
                            throw new Exception("语法错误");
                    }
                    return tag;
                }
                return null;
            }
            #endregion
            #region for
#if ALLOWFOR
            if (text.StartsWith("#for", StringComparison.OrdinalIgnoreCase))
            {
                Match m = ParserRegex.ForRegex.Match(text);
                if (m.Success)
                {
                    ForTag tag = new ForTag(text);
                    tag.Calculate = m.Groups["Calculate"].Value;
                    tag.Determine = m.Groups["Determine"].Value;
                    tag.EndValue = m.Groups["End"].Value;
                    tag.StartValue = m.Groups["Start"].Value;
                    tag.Step = m.Groups["Step"].Value;
                    tag.VarName = m.Groups["Var"].Value;
                    tag.Name = m.Groups["Name"].Value;
                    tag.Cache = !string.IsNullOrEmpty(tag.Name);
                    index++;
                    while (true)
                    {
                        if (index < element.Count)
                        {
                            if (element[index].TokenKind == TokenKind.Tag)
                            {
                                if (element[index].ToString() != null && element[index].ToString().Trim().Equals("#endfor", StringComparison.OrdinalIgnoreCase))
                                    break;
                                else
                                    tag.Element.Add(ProcessTag(element[index].ToString()));
                            }
                            else
                                tag.Element.Add(element[index]);
                            index++;
                        }
                        else
                            throw new Exception("语法错误");
                    }
                    return tag;
                }
            }
#endif
            #endregion
            #region IF
#if ALLOWIF
            if (text.StartsWith("#if(", StringComparison.OrdinalIgnoreCase) && text.EndsWith(")"))
            {
                string _text = text.Remove(0, 4).TrimEnd(')').Trim();
                IfTag tag = new IfTag(text);
                tag.IfCondition = _text;
                int status = 0;//0 if 1 eseif 2else 3endif
                index++;
                while (true)
                {
                    if (index < element.Count)
                    {
                        if (element[index].TokenKind == TokenKind.Tag)
                        {
                            if (element[index].ToString() != null && element[index].ToString().Trim().Equals("#endif", StringComparison.OrdinalIgnoreCase))
                            {
                                return tag;
                            }
                            else if (element[index].ToString() != null && element[index].ToString().Trim().Equals("#else", StringComparison.OrdinalIgnoreCase))
                            {
                                status = 2;
                            }
                            else
                            {
                                string _elseif = element[index].ToString().Trim();
                                if (_elseif.StartsWith("#elseif(", StringComparison.OrdinalIgnoreCase) && text.EndsWith(")"))
                                {
                                    status = 1;
                                    tag.ElseIfCondition.Add(_elseif.Remove(0, 8).TrimEnd(')').Trim());
                                    tag.ElseIfElement.Add(new List<Token>());
                                }
                                else
                                {
                                    switch (status)
                                    {
                                        case 0:
                                            tag.IfElement.Add(ProcessTag(element[index].ToString(), element, ref index));
                                            break;
                                        case 1:
                                            tag.ElseIfElement[tag.ElseIfElement.Count - 1].Add(ProcessTag(element[index].ToString(), element, ref index));
                                            break;
                                        case 2:
                                            tag.ElseElement.Add(ProcessTag(element[index].ToString(), element, ref index));
                                            break;
                                        default:
                                            throw new Exception("语法错误");
                                    }
                                }
                            }
                        }
                        else
                        {
                            switch (status)
                            {
                                case 0:
                                    tag.IfElement.Add(element[index]);
                                    break;
                                case 1:
                                    tag.ElseIfElement[tag.ElseIfElement.Count - 1].Add(element[index]);
                                    break;
                                case 2:
                                    tag.ElseElement.Add(element[index]);
                                    break;
                                default:
                                    throw new Exception("语法错误");
                            }
                        }
                        index++;
                    }
                    else
                        throw new Exception("语法错误");
                }
                return null;
            }
#endif
            #endregion
            return null;
        }

        public virtual List<Token> ParserAll(List<Token> element)
        {
            List<Token> target = new List<Token>();
            int index = 0;

            while (index < element.Count)
            {
                Token token;
                if (element[index].TokenKind == TokenKind.Tag)
                {
                    token = ProcessTag(element[index].ToString(), element, ref index);


                }
                else
                {
                    token = element[index];
                }

                target.Add(token);

                index++;
            }
            return target;
        }
    }
}
